package com.nowcoder.topic.dfs.middle;

/**
 * NC226 被围绕的区域
 * @author d3y1
 */
public class NC226{
    private int[] dx = new int[]{0, 1, 0, -1};
    private int[] dy = new int[]{1, 0, -1, 0};
    private int ROW;
    private int COL;
    private boolean[][] isVisited;

    /**
     * 代码中的类名、方法名、参数名已经指定，请勿修改，直接返回方法规定的值即可
     *
     * 程序入口
     *
     * @param board char字符型二维数组
     * @return char字符型二维数组
     */
    public char[][] surroundedArea (char[][] board) {
        return solution1(board);
//        return solution2(board);
    }

    /**
     * 模拟法: 直接递归
     * @param board
     * @return
     */
    private char[][] solution1(char[][] board){
        ROW = board.length;
        COL = board[0].length;
        isVisited = new boolean[ROW][COL];

        for(int i=0; i<ROW; i++){
            for(int j=0; j<COL; j++){
                if(board[i][j]=='O' && !isVisited[i][j]){
                    dfs(board, i, j);
                }
            }
        }

        return board;
    }

    /**
     * dfs
     * @param board
     * @param x
     * @param y
     * @return
     */
    private boolean dfs(char[][] board, int x, int y){
        if(board[x][y] == 'X'){
            return true;
        }

        // O -> X
        board[x][y] = 'X';
        isVisited[x][y] = true;

        int nextX, nextY;
        for(int i=0; i<4; i++){
            nextX = x+dx[i];
            nextY = y+dy[i];
            // 不合法 超过边界
            if(!isValid(nextX, nextY)){
                // X -> O
                board[x][y] = 'O';
                return false;
            }
            // 未访问过
            if(!isVisited[nextX][nextY]){
                if(!dfs(board, nextX, nextY)){
                    // X -> O
                    board[x][y] = 'O';
                    return false;
                }
            }
            // 已访问过
            else{
                // 已访问过 但是恢复成O => 说明相邻位置(nextX,nextY)未被围绕, 则当前位置(x,y)也不可能被围绕
                if(board[nextX][nextY] == 'O'){
                    // X -> O
                    board[x][y] = 'O';
                    return false;
                }
            }
        }

        return true;
    }

    /**
     * 模拟法: 边界递归
     * @param board
     * @return
     */
    private char[][] solution2(char[][] board){
        ROW = board.length;
        COL = board[0].length;
//        isVisited = new boolean[ROW][COL];

        // 左右边界
        for(int i=0; i<ROW; i++){
            if(board[i][0] == 'O'){
                dfsBorder(board, i, 0);
            }
            if(board[i][COL-1] == 'O'){
                dfsBorder(board, i, COL-1);
            }
        }

        // 上下边界
        for(int j=0; j<COL; j++){
            if(board[0][j] == 'O'){
                dfsBorder(board, 0, j);
            }
            if(board[ROW-1][j] == 'O'){
                dfsBorder(board, ROW-1, j);
            }
        }

        // N -> O and O -> X
        for(int i=0; i<ROW; i++){
            for(int j=0; j<COL; j++){
                if(board[i][j] == 'O'){
                    board[i][j] = 'X';
                }
                if(board[i][j] == 'N'){
                    board[i][j] = 'O';
                }
            }
        }

        return board;
    }

    /**
     * dfs(边界)
     * @param board
     * @param x
     * @param y
     */
    private void dfsBorder(char[][] board, int x, int y){
        // N-NO
        if(board[x][y]=='X' || board[x][y]=='N'){
            return;
        }

        // O -> N
        board[x][y] = 'N';

        int nextX, nextY;
        for(int i=0; i<4; i++){
            nextX = x+dx[i];
            nextY = y+dy[i];
            if(isValid(nextX, nextY)){
                dfsBorder(board, nextX, nextY);
            }
        }
    }

    /**
     * 是否合法(是否越界)
     * @param x
     * @param y
     * @return
     */
    private boolean isValid(int x, int y){
        if(x<0 || x>=ROW || y<0 || y>=COL){
            return false;
        }

        return true;
    }
}